﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using Loom;
using Loom.JoinPoints;
using Kugar.Core.ExtMethod;


namespace Kugar.Core.Security
{
    internal static class AuthorityCheckCache
    {
        
    }

    /// <summary>
    ///     指定一个函数需要进行权限控制,要进行权限控制的函数必须是虚函数,该功能使用的是代理类的方式
    /// </summary>
    /// <example>
    /// 如： <br/>
    ///    [AuthorityCheck]<br/>
    ///    [AuthorityNeed("Sale.NewOrder","Stock.ChangeQty")]<br/>
    ///     public virtual void Insert(){} <br/>
    /// 
    ///   [AuthorityCheck]<br/>
    ///    public virtual int Qty<br/>
    ///   {<br/>
    ///       [AuthorityNeed("SaleDetail.SetQty")]<br/>
    ///       set;<br/>
    /// <br/>
    ///       [AuthorityNeed("SaleDetail.GetQty")]<br/>
    ///       get;<br/>
    ///   }<br/>
    /// </example>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class AuthorityCheckAttribute : AspectAttribute
    {
        [IncludeAll]            // includes all methods
        [Call(Advice.Around)]   // aspect method is called instead of the target method
        [Access(Advice.Around)]
        public T CheckPermission<T>([JPContext] Context context, params object[] parameters)
        {
            var igonCheck = GetIgnoreState();

            if (!igonCheck.GetValueOrDefault() && context.CurrentMethod.HasAttribute(typeof(IgnorePermissionCheckAttribute), true))
            {
                igonCheck = true;
                BeginIgnore();
            }


            //TODO:忽略用户权限检查的权限

            if (!igonCheck.GetValueOrDefault())
            {
                var attr = context.CurrentMethod.GetAttribute<AuthorityNeedAttribute>();

                if (attr != null)
                {
                    var provider = CurrentUserPermissionProvider();

                    string[] failList = null;

                    switch (attr.AuthorityType)
                    {
                           case AuthorityType.PermissionID:
                                var tempCheckIDList = provider.CheckPermissionByIDList(attr.PermissionIDList);
                            
                                if (tempCheckIDList != null && tempCheckIDList.Length > 0)
                                {
                                    failList = tempCheckIDList.Where(k => k.Value <= 0).Select(k => k.Key.ToString()).ToArray();
                                }
                            break;

                            case AuthorityType.PermissionName:
                                var tempCheckNameList = provider.CheckPermissionByNameList(attr.PermissionNameList);
                                if (tempCheckNameList!=null && tempCheckNameList.Length>0)
                                {
                                    failList = tempCheckNameList.Where(k => k.Value <= 0).Select(k => k.Key.ToString()).ToArray();
                                }
                            break;
                    }

                    if (failList!=null && failList.Length>0)
                    {
                        if (attr.HandlerType == AuthorityFailHandler.ReturnDefaultValue)
                        {
                            EndIgnore();
                            return (T)Convert.ChangeType(attr.DefaultValue,typeof(T));
                        }
                        else
                        {
                            EndIgnore();
                            throw new AuthorityFailException(failList);
                        }
                    }
                }
            }

            T ret;

            try
            {
                ret = (T)context.Invoke(parameters);
                return ret;
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                EndIgnore();
            }
        }

        /// <summary>
        ///     停止当前线程的取消权限验证
        /// </summary>
        public void EndIgnore()
        {
            CallContext.LogicalSetData("IgnorePermission", false);

            CallContext.FreeNamedDataSlot("IgnorePermission");
        }

        /// <summary>
        ///     开始在当前线程取消权限验证
        /// </summary>
        public void BeginIgnore()
        {
            CallContext.LogicalSetData("IgnorePermission", true);
        }

        private bool? GetIgnoreState()
        {
            return (bool?)CallContext.GetData("IgnorePermission");
        }

        public static Func<IPermissionCheckProvider> CurrentUserPermissionProvider { set; get; }

    }


    public class AuthorityFailException:Exception
    {
        public AuthorityFailException(string[] permissionList)
            : base("权限验证失败,当前用户不具备以下权限： \r\n" + permissionList.JoinToString('\n'))
        {
        }
    }

    /// <summary>
    ///     指定一个函数调用时需要哪些权限
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class AuthorityNeedAttribute : Attribute
    {
        protected AuthorityNeedAttribute()
        {
            HandlerType = AuthorityFailHandler.ThrowException;
        }

        public AuthorityNeedAttribute(params int[] permissionID)
            : this()
        {
            PermissionIDList = permissionID;
            AuthorityType = AuthorityType.PermissionID;
        }

        public AuthorityNeedAttribute(object defaultValue, params int[] permissionID)
            : this()
        {
            HandlerType = AuthorityFailHandler.ReturnDefaultValue;
            DefaultValue = defaultValue;
            PermissionIDList = permissionID;
            AuthorityType = AuthorityType.PermissionID;
        }

        public AuthorityNeedAttribute(params string[] permissionName)
            : this()
        {
            PermissionNameList = permissionName;
            AuthorityType = AuthorityType.PermissionName;
        }

        public AuthorityNeedAttribute(object defaultValue, params string[] permissionName)
            : this()
        {
            HandlerType = AuthorityFailHandler.ReturnDefaultValue;
            DefaultValue = defaultValue;
            PermissionNameList = permissionName;
            AuthorityType = AuthorityType.PermissionName;
        }

        public object DefaultValue { get; protected set; }

        public int[] PermissionIDList { get; protected set; }

        public string[] PermissionNameList { get; protected set; }

        public AuthorityFailHandler HandlerType { set; get; }

        public AuthorityType AuthorityType { get; protected set; }
    }

    /// <summary>
    ///     权限验证失败时的处理方式
    /// </summary>
    public enum AuthorityFailHandler
    {
        /// <summary>
        ///     抛出错误
        /// </summary>
        ThrowException,

        /// <summary>
        ///     返回默认值
        /// </summary>
        ReturnDefaultValue

    }

    /// <summary>
    ///     权限验证方式
    /// </summary>
    public enum AuthorityType
    {
        /// <summary>
        ///     使用权限名验证
        /// </summary>
        PermissionName,

        /// <summary>
        ///     使用权限ID验证
        /// </summary>
        PermissionID
    }



    /// <summary>
    ///     指定一个函数在调用范围内，忽略权限检查
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class IgnorePermissionCheckAttribute : Attribute
    {

    }

}
